package cn.kevinkun.PdfViewer;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.SimpleEvent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.UsesAssets;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.Component;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.EventDispatcher;
import com.google.appinventor.components.runtime.HVArrangement;
import com.google.appinventor.components.runtime.OnDestroyListener;
import com.google.appinventor.components.runtime.ReplForm;
import com.google.appinventor.components.runtime.util.FileUtil;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

@DesignerComponent(version = 2, versionName = "2.1", category = ComponentCategory.EXTENSION, description = "In-app pdf viewer with pdf.js. ", iconName = "images/extension.png", nonVisible = true, helpUrl = "https://www.kevinkun.cn/pdfviewer")
@SimpleObject(external = true)
@UsesAssets(fileNames = "index.html, index.js, pdf.min.js, pdf.worker.min.js")

public class KevinkunPdfViewer extends AndroidNonvisibleComponent implements Component, OnDestroyListener {
	private Activity activity;
	private Context context;
	WebView webView;
	ViewGroup ll;
	String pdfFullPath;

	public KevinkunPdfViewer(ComponentContainer container) {
		super(container.$form());
		this.activity = container.$context();
		this.context = container.$context();
	}

	@SuppressLint({ "SetJavaScriptEnabled" })
	@SimpleFunction(description = "Load the pdf to layout. pdfPath: like '//assets.pdf', or 'asd.pdf'")
	public void LoadPDF(HVArrangement layout, String pdfPath) {
		if (!pdfPath.toLowerCase().endsWith(".pdf")) {
			OnError("ONLY SUPPORT PDF FILE");
			return;
		}
		pdfFullPath = getAbsolutePath(pdfPath);
		File f = new File(pdfFullPath);
		if (!f.exists()) {
			OnError("FILE NOT FOUND");
			return;
		}

		ViewGroup viewGroup = (ViewGroup) layout.getView();
		viewGroup.removeAllViews();
		this.webView = new WebView(this.activity);
		viewGroup.addView(this.webView);

		WebSettings webSettings = this.webView.getSettings();
		webSettings.setJavaScriptEnabled(true);
		webSettings.setSupportZoom(true);
		webSettings.setBuiltInZoomControls(true);
		webSettings.setDisplayZoomControls(false);
		webSettings.setAllowFileAccess(true);
		webSettings.setAllowFileAccessFromFileURLs(true);
		webSettings.setAllowUniversalAccessFromFileURLs(true);

		webSettings.setCacheMode(1);

		webSettings.setDomStorageEnabled(true);

		this.webView.addJavascriptInterface(new JsObject(), "PdfViewer");
		webView.setWebViewClient(webViewClient);
		try {
			this.webView.loadUrl(this.form.getAssetPathForExtension(this, "index.html"));
		} catch (IOException localIOException) {
			OnError("INTERAL ERROR");
		}
	}

	WebViewClient webViewClient = new WebViewClient() {
		@Override
		public void onPageFinished(WebView view, String url) {
			webView.evaluateJavascript("loadPdf('file://" + pdfFullPath + "');", null);
		}
	};

	@SimpleFunction(description = "show the pdf. pageRange like '1', or '2-5', or '1,3-5'. Leave empty for all")
	public void Preview(String pageRange) {
		if (pageRange.trim().equals("")) {
			pageRange = "1-";
		}
		this.webView.evaluateJavascript("preview('" + pageRange + "');", null);
	}

	@SimpleFunction(description = "scroll to the page smoothly")
	public void Goto(int page) {
		this.webView.evaluateJavascript("goto(" + page + ");", null);
	}

	@SimpleEvent
	public void OnError(String error) {
		EventDispatcher.dispatchEvent(this, "OnError", new Object[] { error });
	}

	@SimpleEvent
	public void PdfLoaded(String totalPage) {
		EventDispatcher.dispatchEvent(this, "PdfLoaded", new Object[] { totalPage });
	}

	@SimpleEvent
	public void Scrolled(String pageInView) {
		EventDispatcher.dispatchEvent(this, "Scrolled", new Object[] { pageInView });
	}

	private String getAbsolutePath(String filename) {
		filename = filename.replaceAll("file://", "");
		String result = "";

		if (filename.startsWith("//")) {
			filename = filename.substring(2);
			if (ReplForm.class.isInstance(this.form)) {
				String asd = this.context.getExternalFilesDir(null).getPath();
				if (Build.VERSION.SDK_INT >= 29) {
					result = asd + "/assets/" + filename;
				} else {
					result = asd + "/AppInventor/assets/" + filename;
				}
			} else {
				result = this.context.getFilesDir().getPath() + "/" + filename;
				try {
					InputStream in = this.form.openAsset(filename);
					FileUtil.writeStreamToFile(in, result);
				} catch (IOException localIOException) {

				}
			}
		} else if (filename.startsWith("/storage/emulated/")) {
			result = filename;
		} else if (filename.startsWith("/")) {
			result = this.context.getExternalFilesDir(null).getPath() + filename;
		} else {
			result = this.context.getExternalFilesDir(null).getPath() + "/" + filename;
		}
		return result;
	}

	private class JsObject {
		private JsObject() {
		}

		@JavascriptInterface
		public void pdfReady(final String totalpage) {
			KevinkunPdfViewer.this.activity.runOnUiThread(new Runnable() {
				public void run() {
					KevinkunPdfViewer.this.PdfLoaded(totalpage);
				}
			});
		}

		@JavascriptInterface
		public void scrolled(final String pageInview) {
			KevinkunPdfViewer.this.activity.runOnUiThread(new Runnable() {
				public void run() {
					KevinkunPdfViewer.this.Scrolled(pageInview);
				}
			});
		}

		@JavascriptInterface
		public void error(final String reason) {
			KevinkunPdfViewer.this.activity.runOnUiThread(new Runnable() {
				public void run() {
					KevinkunPdfViewer.this.OnError(reason);
				}
			});
		}
	}

	@Override
	public void onDestroy() {
		ll.removeAllViews();
		webView.stopLoading();
		webView.removeAllViews();
		webView.destroy();
		webView = null;
		ll = null;

	}

}
